package com.candy.databasedocuments.service.document;

import com.candy.databasedocuments.entity.Table;
import com.candy.databasedocuments.entity.TableFieldInfo;
import com.candy.databasedocuments.entity.TableKeyInfo;
import com.candy.databasedocuments.service.AbstractDocumentService;
import com.candy.databasedocuments.utils.ToolsUtils;
import com.candy.databasedocuments.utils.WordTableUtil;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlException;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.springframework.stereotype.Service;

import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author suYanLong
 * @version 1.0
 * @date 2023/7/6 9:04
 * @Description word文档
 */
@Service
public class WordDocumentServiceImpl extends AbstractDocumentService {

    @Override
    public String tableToDocument(List<Table> tableList) throws XmlException, IOException {
        XWPFDocument document = new XWPFDocument();
        Map<String, List<Table>> map = tableList.stream().collect(Collectors.groupingBy(Table::getTableName));
        map = sortByKey(map);
        Set<Map.Entry<String, List<Table>>> entries = map.entrySet();
        double num = 1.00;
        double add = 0.01;

        String heading1 = "My Heading 1";
        String heading2 = "My Heading 2";
        String heading3 = "My Heading 3";
        String heading4 = "My Heading 4";
        boolean first = true;
        for (Table table : tableList) {
            String tableName = table.getTableName();
            String tableRemark = table.getTableRemark();
            List<TableFieldInfo> tableFieldInfoList = table.getFields();
            List<TableKeyInfo> keys = table.getKeys();

            XWPFStyles styles = document.createStyles();
            if (first) {
                first = false;
                addCustomHeadingStyle(document, styles, heading1, 1, 36, "000000");
                addCustomHeadingStyle(document, styles, heading2, 2, 28, "000000");
                addCustomHeadingStyle(document, styles, heading3, 3, 24, "000000");
                addCustomHeadingStyle(document, styles, heading4, 4, 20, "000000");
            }

            double result = num + add;
            add = add + 0.01;
            String formatResult = String.format("%.2f", result);

            // 设置标题目录
            XWPFParagraph paragraph1 = document.createParagraph();
            XWPFRun run1 = paragraph1.createRun();
            paragraph1.setAlignment(ParagraphAlignment.LEFT);
            paragraph1.setStyle(heading1);
            run1.setText(formatResult + " " + "表名:" + tableName + tableRemark);
            run1.setBold(true); // 加粗

            XWPFParagraph paragraph11 = document.createParagraph();
            XWPFRun run11 = paragraph11.createRun();
            paragraph11.setAlignment(ParagraphAlignment.LEFT);
            paragraph11.setStyle(heading2);
            run11.setText(formatResult + ".1 " + "表结构信息");
            run11.setBold(true); // 加粗

            XWPFTable xwpfTable = WordTableUtil.getTable(document, 3 + tableFieldInfoList.size(), 7);
            WordTableUtil.fillNullDataField(xwpfTable, 0, 0, 3 + tableFieldInfoList.size(), 7, null);
            WordTableUtil.fillReallyDataField(xwpfTable, 2, 0, tableFieldInfoList.size() + 2, 7, tableFieldInfoList);
            XWPFTableCell cell = xwpfTable.getRow(0).getCell(1);
            cell.setText(tableName);

//            XWPFParagraph paragraph2 = document.createParagraph();
//            XWPFRun run2 = paragraph2.createRun();
//            run2.setText("");

            XWPFParagraph paragraph12 = document.createParagraph();
            XWPFRun run12 = paragraph12.createRun();
            paragraph12.setAlignment(ParagraphAlignment.LEFT);
            paragraph12.setStyle(heading2);
            run12.setText(formatResult + ".2 " + "表索引信息");
            run12.setBold(true); // 加粗

            XWPFTable xwpfTableIndex = WordTableUtil.getTable(document, 3 + keys.size(), 5);
            WordTableUtil.fillNullData(xwpfTableIndex, 0, 0, 3 + keys.size(), 5, null);
            WordTableUtil.fillReallyData(xwpfTableIndex, 2, 0, keys.size() + 2, 5, keys);
            XWPFTableCell cellIndex = xwpfTableIndex.getRow(0).getCell(1);
            cellIndex.setText(tableName);

            XWPFParagraph paragraph4 = document.createParagraph();
            XWPFRun run4 = paragraph4.createRun();
            run4.setText("");
        }

        FileOutputStream out = null;
        String filePath = databaseConfig.getDcAttr().getPath() + ToolsUtils.getFileName("docx");
        try {
            out = new FileOutputStream(filePath);
            document.write(out);
            out.close();
            document.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return filePath;
    }

    public <K extends Comparable<? super K>, V> Map<K, V> sortByKey(Map<K, V> map) {
        Map<K, V> result = new LinkedHashMap<>();

        map.entrySet().stream()
                .sorted(Map.Entry.<K, V>comparingByKey()).forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
        return result;

    }

    private static void addCustomHeadingStyle(XWPFDocument docxDocument, XWPFStyles styles, String strStyleId, int headingLevel, int pointSize, String hexColor) {

        CTStyle ctStyle = CTStyle.Factory.newInstance();
        ctStyle.setStyleId(strStyleId);

        CTString styleName = CTString.Factory.newInstance();
        styleName.setVal(strStyleId);
        ctStyle.setName(styleName);

        CTDecimalNumber indentNumber = CTDecimalNumber.Factory.newInstance();
        indentNumber.setVal(BigInteger.valueOf(headingLevel));

        // lower number > style is more prominent in the formats bar
        ctStyle.setUiPriority(indentNumber);

        CTOnOff onoffnull = CTOnOff.Factory.newInstance();
        ctStyle.setUnhideWhenUsed(onoffnull);

        // style shows up in the formats bar
        ctStyle.setQFormat(onoffnull);

        // style defines a heading of the given level
        CTPPr ppr = CTPPr.Factory.newInstance();
        ppr.setOutlineLvl(indentNumber);
        ctStyle.setPPr(ppr);

        XWPFStyle style = new XWPFStyle(ctStyle);

        CTHpsMeasure size = CTHpsMeasure.Factory.newInstance();
        size.setVal(new BigInteger(String.valueOf(pointSize)));
        CTHpsMeasure size2 = CTHpsMeasure.Factory.newInstance();
        size2.setVal(new BigInteger("24"));

        CTFonts fonts = CTFonts.Factory.newInstance();
        fonts.setAscii("Loma");

        CTRPr rpr = CTRPr.Factory.newInstance();
        rpr.setRFonts(fonts);
        rpr.setSz(size);
        rpr.setSzCs(size2);

        CTColor color = CTColor.Factory.newInstance();
        color.setVal(hexToBytes(hexColor));
        rpr.setColor(color);
        style.getCTStyle().setRPr(rpr);
        // is a null op if already defined

        style.setType(STStyleType.PARAGRAPH);
        styles.addStyle(style);

    }

    public static byte[] hexToBytes(String hexString) {
        HexBinaryAdapter adapter = new HexBinaryAdapter();
        byte[] bytes = adapter.unmarshal(hexString);
        return bytes;
    }

}
